<?php

// 公共助手函数

use think\exception\HttpResponseException;
use think\Response;
use think\Session;
if (!function_exists('__')) {

    /**
     * 获取语言变量值
     * @param string $name 语言变量名
     * @param string | array  $vars 动态变量值
     * @param string $lang 语言
     * @return mixed
     */
    function __($name, $vars = [], $lang = '')
    {
        if (is_numeric($name) || !$name) {
            return $name;
        }
        if (!is_array($vars)) {
            $vars = func_get_args();
            array_shift($vars);
            $lang = '';
        }
        return \think\Lang::get($name, $vars, $lang);
    }
}

if (!function_exists('format_bytes')) {

    /**
     * 将字节转换为可读文本
     * @param int    $size      大小
     * @param string $delimiter 分隔符
     * @param int    $precision 小数位数
     * @return string
     */
    function format_bytes($size, $delimiter = '', $precision = 2)
    {
        $units = array('B', 'KB', 'MB', 'GB', 'TB', 'PB');
        for ($i = 0; $size >= 1024 && $i < 5; $i++) {
            $size /= 1024;
        }
        return round($size, $precision) . $delimiter . $units[$i];
    }
}

if (!function_exists('datetime')) {

    /**
     * 将时间戳转换为日期时间
     * @param int    $time   时间戳
     * @param string $format 日期时间格式
     * @return string
     */
    function datetime($time, $format = 'Y-m-d H:i:s')
    {
        $time = is_numeric($time) ? $time : strtotime($time);
        return date($format, $time);
    }
}

if (!function_exists('human_date')) {

    /**
     * 获取语义化时间
     * @param int $time  时间
     * @param int $local 本地时间
     * @return string
     */
    function human_date($time, $local = null)
    {
        return \fast\Date::human($time, $local);
    }
}

if (!function_exists('cdnurl')) {

    /**
     * 获取上传资源的CDN的地址
     * @param string  $url    资源相对地址
     * @param boolean $domain 是否显示域名 或者直接传入域名
     * @return string
     */
    function cdnurl($url, $domain = false)
    {
        $regex = "/^((?:[a-z]+:)?\/\/|data:image\/)(.*)/i";
        $cdnurl = \think\Config::get('upload.cdnurl');
        if (is_bool($domain) || stripos($cdnurl, '/') === 0) {
            $url = preg_match($regex, $url) || ($cdnurl && stripos($url, $cdnurl) === 0) ? $url : $cdnurl . $url;
        }
        if ($domain && !preg_match($regex, $url)) {
            $domain = is_bool($domain) ? request()->domain() : $domain;
            $url = $domain . $url;
        }
        return $url;
    }
}


if (!function_exists('is_really_writable')) {

    /**
     * 判断文件或文件夹是否可写
     * @param string $file 文件或目录
     * @return    bool
     */
    function is_really_writable($file)
    {
        if (DIRECTORY_SEPARATOR === '/') {
            return is_writable($file);
        }
        if (is_dir($file)) {
            $file = rtrim($file, '/') . '/' . md5(mt_rand());
            if (($fp = @fopen($file, 'ab')) === false) {
                return false;
            }
            fclose($fp);
            @chmod($file, 0777);
            @unlink($file);
            return true;
        } elseif (!is_file($file) or ($fp = @fopen($file, 'ab')) === false) {
            return false;
        }
        fclose($fp);
        return true;
    }
}

if (!function_exists('rmdirs')) {

    /**
     * 删除文件夹
     * @param string $dirname  目录
     * @param bool   $withself 是否删除自身
     * @return boolean
     */
    function rmdirs($dirname, $withself = true)
    {
        if (!is_dir($dirname)) {
            return false;
        }
        $files = new RecursiveIteratorIterator(
            new RecursiveDirectoryIterator($dirname, RecursiveDirectoryIterator::SKIP_DOTS),
            RecursiveIteratorIterator::CHILD_FIRST
        );

        foreach ($files as $fileinfo) {
            $todo = ($fileinfo->isDir() ? 'rmdir' : 'unlink');
            $todo($fileinfo->getRealPath());
        }
        if ($withself) {
            @rmdir($dirname);
        }
        return true;
    }
}

if (!function_exists('copydirs')) {

    /**
     * 复制文件夹
     * @param string $source 源文件夹
     * @param string $dest   目标文件夹
     */
    function copydirs($source, $dest)
    {
        if (!is_dir($dest)) {
            mkdir($dest, 0755, true);
        }
        foreach (
            $iterator = new RecursiveIteratorIterator(
                new RecursiveDirectoryIterator($source, RecursiveDirectoryIterator::SKIP_DOTS),
                RecursiveIteratorIterator::SELF_FIRST
            ) as $item
        ) {
            if ($item->isDir()) {
                $sontDir = $dest . DS . $iterator->getSubPathName();
                if (!is_dir($sontDir)) {
                    mkdir($sontDir, 0755, true);
                }
            } else {
                copy($item, $dest . DS . $iterator->getSubPathName());
            }
        }
    }
}

if (!function_exists('mb_ucfirst')) {
    function mb_ucfirst($string)
    {
        return mb_strtoupper(mb_substr($string, 0, 1)) . mb_strtolower(mb_substr($string, 1));
    }
}

if (!function_exists('addtion')) {

    /**
     * 附加关联字段数据
     * @param array $items  数据列表
     * @param mixed $fields 渲染的来源字段
     * @return array
     */
    function addtion($items, $fields)
    {
        if (!$items || !$fields) {
            return $items;
        }
        $fieldsArr = [];
        if (!is_array($fields)) {
            $arr = explode(',', $fields);
            foreach ($arr as $k => $v) {
                $fieldsArr[$v] = ['field' => $v];
            }
        } else {
            foreach ($fields as $k => $v) {
                if (is_array($v)) {
                    $v['field'] = $v['field'] ?? $k;
                } else {
                    $v = ['field' => $v];
                }
                $fieldsArr[$v['field']] = $v;
            }
        }
        foreach ($fieldsArr as $k => &$v) {
            $v = is_array($v) ? $v : ['field' => $v];
            $v['display'] = $v['display'] ?? str_replace(['_ids', '_id'], ['_names', '_name'], $v['field']);
            $v['primary'] = $v['primary'] ?? '';
            $v['column'] = $v['column'] ?? 'name';
            $v['model'] = $v['model'] ?? '';
            $v['table'] = $v['table'] ?? '';
            $v['name'] = $v['name'] ?? str_replace(['_ids', '_id'], '', $v['field']);
        }
        unset($v);
        $ids = [];
        $fields = array_keys($fieldsArr);
        foreach ($items as $k => $v) {
            foreach ($fields as $m => $n) {
                if (isset($v[$n])) {
                    $ids[$n] = array_merge(isset($ids[$n]) && is_array($ids[$n]) ? $ids[$n] : [], explode(',', $v[$n]));
                }
            }
        }
        $result = [];
        foreach ($fieldsArr as $k => $v) {
            if ($v['model']) {
                $model = new $v['model'];
            } else {
                // 优先判断使用table的配置
                $model = $v['table'] ? \think\Db::table($v['table']) : \think\Db::name($v['name']);
            }
            $primary = $v['primary'] ?: $model->getPk();
            $result[$v['field']] = isset($ids[$v['field']]) ? $model->where($primary, 'in', $ids[$v['field']])->column($v['column'], $primary) : [];
        }

        foreach ($items as $k => &$v) {
            foreach ($fields as $m => $n) {
                if (isset($v[$n])) {
                    $curr = array_flip(explode(',', $v[$n]));

                    $linedata = array_intersect_key($result[$n], $curr);
                    $v[$fieldsArr[$n]['display']] = $fieldsArr[$n]['column'] == '*' ? $linedata : implode(',', $linedata);
                }
            }
        }
        return $items;
    }
}

if (!function_exists('var_export_short')) {

    /**
     * 使用短标签打印或返回数组结构
     * @param mixed   $data
     * @param boolean $return 是否返回数据
     * @return string
     */
    function var_export_short($data, $return = true)
    {
        return var_export($data, $return);
    }
}

if (!function_exists('letter_avatar')) {
    /**
     * 首字母头像
     * @param $text
     * @return string
     */
    function letter_avatar($text)
    {
        $total = unpack('L', hash('adler32', $text, true))[1];
        $hue = $total % 360;
        list($r, $g, $b) = hsv2rgb($hue / 360, 0.3, 0.9);

        $bg = "rgb({$r},{$g},{$b})";
        $color = "#ffffff";
        $first = mb_strtoupper(mb_substr($text, 0, 1));
        $src = base64_encode('<svg xmlns="http://www.w3.org/2000/svg" version="1.1" height="100" width="100"><rect fill="' . $bg . '" x="0" y="0" width="100" height="100"></rect><text x="50" y="50" font-size="50" text-copy="fast" fill="' . $color . '" text-anchor="middle" text-rights="admin" dominant-baseline="central">' . $first . '</text></svg>');
        $value = 'data:image/svg+xml;base64,' . $src;
        return $value;
    }
}

if (!function_exists('hsv2rgb')) {
    function hsv2rgb($h, $s, $v)
    {
        $r = $g = $b = 0;

        $i = floor($h * 6);
        $f = $h * 6 - $i;
        $p = $v * (1 - $s);
        $q = $v * (1 - $f * $s);
        $t = $v * (1 - (1 - $f) * $s);

        switch ($i % 6) {
            case 0:
                $r = $v;
                $g = $t;
                $b = $p;
                break;
            case 1:
                $r = $q;
                $g = $v;
                $b = $p;
                break;
            case 2:
                $r = $p;
                $g = $v;
                $b = $t;
                break;
            case 3:
                $r = $p;
                $g = $q;
                $b = $v;
                break;
            case 4:
                $r = $t;
                $g = $p;
                $b = $v;
                break;
            case 5:
                $r = $v;
                $g = $p;
                $b = $q;
                break;
        }

        return [
            floor($r * 255),
            floor($g * 255),
            floor($b * 255)
        ];
    }
}

if (!function_exists('check_nav_active')) {
    /**
     * 检测会员中心导航是否高亮
     */
    function check_nav_active($url, $classname = 'active')
    {
        $auth = \app\common\library\Auth::instance();
        $requestUrl = $auth->getRequestUri();
        $url = ltrim($url, '/');
        return $requestUrl === str_replace(".", "/", $url) ? $classname : '';
    }
}

if (!function_exists('check_cors_request')) {
    /**
     * 跨域检测
     */
    function check_cors_request()
    {
        if (isset($_SERVER['HTTP_ORIGIN']) && $_SERVER['HTTP_ORIGIN'] && config('fastadmin.cors_request_domain')) {
            $info = parse_url($_SERVER['HTTP_ORIGIN']);
            $domainArr = explode(',', config('fastadmin.cors_request_domain'));
            $domainArr[] = request()->host(true);
            if (in_array("*", $domainArr) || in_array($_SERVER['HTTP_ORIGIN'], $domainArr) || (isset($info['host']) && in_array($info['host'], $domainArr))) {
                header("Access-Control-Allow-Origin: " . $_SERVER['HTTP_ORIGIN']);
            } else {
                $response = Response::create('跨域检测无效', 'html', 403);
                throw new HttpResponseException($response);
            }

            header('Access-Control-Allow-Credentials: true');
            header('Access-Control-Max-Age: 86400');

            if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
                if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD'])) {
                    header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS");
                }
                if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS'])) {
                    header("Access-Control-Allow-Headers: {$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']}");
                }
                $response = Response::create('', 'html');
                throw new HttpResponseException($response);
            }
        }
    }
}

if (!function_exists('xss_clean')) {
    /**
     * 清理XSS
     */
    function xss_clean($content, $is_image = false)
    {
        return \app\common\library\Security::instance()->xss_clean($content, $is_image);
    }
}

if (!function_exists('url_clean')) {
    /**
     * 清理URL
     */
    function url_clean($url)
    {
        if (!check_url_allowed($url)) {
            return '';
        }
        return xss_clean($url);
    }
}

if (!function_exists('check_ip_allowed')) {
    /**
     * 检测IP是否允许
     * @param string $ip IP地址
     */
    function check_ip_allowed($ip = null)
    {
        $ip = is_null($ip) ? request()->ip() : $ip;
        $forbiddenipArr = config('site.forbiddenip');
        $forbiddenipArr = !$forbiddenipArr ? [] : $forbiddenipArr;
        $forbiddenipArr = is_array($forbiddenipArr) ? $forbiddenipArr : array_filter(explode("\n", str_replace("\r\n", "\n", $forbiddenipArr)));
        if ($forbiddenipArr && \Symfony\Component\HttpFoundation\IpUtils::checkIp($ip, $forbiddenipArr)) {
            $response = Response::create('请求无权访问', 'html', 403);
            throw new HttpResponseException($response);
        }
    }
}

if (!function_exists('check_url_allowed')) {
    /**
     * 检测URL是否允许
     * @param string $url URL
     * @return bool
     */
    function check_url_allowed($url = '')
    {
        //允许的主机列表
        $allowedHostArr = [
            strtolower(request()->host())
        ];

        if (empty($url)) {
            return true;
        }

        //如果是站内相对链接则允许
        if (preg_match("/^[\/a-z][a-z0-9][a-z0-9\.\/]+((\?|#).*)?\$/i", $url) && substr($url, 0, 2) !== '//') {
            return true;
        }

        //如果是站外链接则需要判断HOST是否允许
        if (preg_match("/((http[s]?:\/\/)+((?>[a-z\-0-9]{2,}\.)+[a-z]{2,8}|((?>([0-9]{1,3}\.)){3}[0-9]{1,3}))(:[0-9]{1,5})?)(?:\s|\/)/i", $url)) {
            $chkHost = parse_url(strtolower($url), PHP_URL_HOST);
            if ($chkHost && in_array($chkHost, $allowedHostArr)) {
                return true;
            }
        }

        return false;
    }
}

if (!function_exists('build_suffix_image')) {
    /**
     * 生成文件后缀图片
     * @param string $suffix 后缀
     * @param null   $background
     * @return string
     */
    function build_suffix_image($suffix, $background = null)
    {
        $suffix = mb_substr(strtoupper($suffix), 0, 4);
        $total = unpack('L', hash('adler32', $suffix, true))[1];
        $hue = $total % 360;
        list($r, $g, $b) = hsv2rgb($hue / 360, 0.3, 0.9);

        $background = $background ? $background : "rgb({$r},{$g},{$b})";

        $icon = <<<EOT
        <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
            <path style="fill:#E2E5E7;" d="M128,0c-17.6,0-32,14.4-32,32v448c0,17.6,14.4,32,32,32h320c17.6,0,32-14.4,32-32V128L352,0H128z"/>
            <path style="fill:#B0B7BD;" d="M384,128h96L352,0v96C352,113.6,366.4,128,384,128z"/>
            <polygon style="fill:#CAD1D8;" points="480,224 384,128 480,128 "/>
            <path style="fill:{$background};" d="M416,416c0,8.8-7.2,16-16,16H48c-8.8,0-16-7.2-16-16V256c0-8.8,7.2-16,16-16h352c8.8,0,16,7.2,16,16 V416z"/>
            <path style="fill:#CAD1D8;" d="M400,432H96v16h304c8.8,0,16-7.2,16-16v-16C416,424.8,408.8,432,400,432z"/>
            <g><text><tspan x="220" y="380" font-size="124" font-family="Verdana, Helvetica, Arial, sans-serif" fill="white" text-anchor="middle">{$suffix}</tspan></text></g>
        </svg>
EOT;
        return $icon;
    }
}
function is_mobile_request(){
    // 如果有HTTP_X_WAP_PROFILE则一定是移动设备
    if (isset ($_SERVER['HTTP_X_WAP_PROFILE']))
    {
        return true;
    }
    // 如果via信息含有wap则一定是移动设备
    if (isset ($_SERVER['HTTP_VIA']))
    {
        // 找不到为flase,否则为true
        return stristr($_SERVER['HTTP_VIA'], "wap") ? true : false;
    }
    // 脑残法，判断手机发送的客户端标志,兼容性有待提高
    if (isset ($_SERVER['HTTP_USER_AGENT']))
    {
        /*$clientkeywords = array ('nokia',
            'sony',
            'ericsson',
            'mot',
            'samsung',
            'htc',
            'sgh',
            'lg',
            'sharp',
            'sie-',
            'philips',
            'panasonic',
            'alcatel',
            'lenovo',
            'iphone',
            'ipod',
            'blackberry',
            'meizu',
            'android',
            'netfront',
            'symbian',
            'ucweb',
            'windowsce',
            'palm',
            'operamini',
            'operamobi',
            'openwave',
            'nexusone',
            'cldc',
            'midp',
            'wap',
            'mobile'
        );
        // 从HTTP_USER_AGENT中查找手机浏览器的关键字
        if (preg_match("/(" . implode('|', $clientkeywords) . ")/i", strtolower($_SERVER['HTTP_USER_AGENT'])))
        {
            return true;
        }*/

        // 平板电脑的常用User Agent关键字
        $tabletKeywords = array('iPad', 'Android', 'Silk', 'Kindle', 'Tablet', 'MIDP', 'mobile tablet', 'Samsung Galaxy Tab');
        // 手机端的常用User Agent关键字
        $mobileKeywords = array('mobile', 'android', 'iphone', 'ipod', 'blackberry', 'opera mini', 'opera mobi', 'windows phone', 'palm', 'nokia', 'sonyericsson', 'mobile safari', 'htc', 'dopod', 'netfront', 'ucweb', 'blazer', 'avantgo', 'plucker', 'xiino', 'blaz-browser', 'meego', 'symbian', 'smartphone', 'midp', 'wap', 'phone', 'windows ce', 'pocket', 'psp', 'symbian', 'mobile+');
        // 如果包含平板电脑的关键词，则返回"tablet"
        $userAgent = $_SERVER['HTTP_USER_AGENT'];
        $userAgent = strtolower($userAgent);
        foreach ($tabletKeywords as $keyword) {
            if (stripos($userAgent, $keyword) != false) {
                return true;
            }
        }

        // 如果包含手机端的关键词，则返回"mobile"
        foreach ($mobileKeywords as $keyword) {
            if (stripos($userAgent, $keyword) != false) {
                return true;
            }
        }
    }
    // 协议法，因为有可能不准确，放到最后判断
    if (isset ($_SERVER['HTTP_ACCEPT']))
    {
        // 如果只支持wml并且不支持html那一定是移动设备
        // 如果支持wml和html但是wml在html之前则是移动设备
        if ((strpos($_SERVER['HTTP_ACCEPT'], 'vnd.wap.wml') !== false) && (strpos($_SERVER['HTTP_ACCEPT'], 'text/html') === false || (strpos($_SERVER['HTTP_ACCEPT'], 'vnd.wap.wml') < strpos($_SERVER['HTTP_ACCEPT'], 'text/html'))))
        {
            return true;
        }
    }
    return false;
}
function getAdminInfo($key = ''){
    $admin = Session::get('admin');
    if(!empty($admin)){
        $admin = $admin[$key];
    }
    return $admin;

}
    /**
     * PHP格式化字节大小
     * @param  number $size      字节数
     * @param  string $delimiter 数字和单位分隔符
     * @return string            格式化后的带单位的大小
     */
    function format_bytes($size, $delimiter = '') {
        $units = array('B', 'KB', 'MB', 'GB', 'TB', 'PB');
        for ($i = 0; $size >= 1024 && $i < 5; $i++) $size /= 1024;
        return round($size, 2) . $delimiter . $units[$i];
    }

    function trace_log($log,$index='default',$time = '',$ip = ''){
        //记录日志
    //    $url = request()->domain();
        if(empty($ip)){
            $ip = getRealIP();
        }
        if(empty($time)){
            $time = time();
        }


        $runPath = RUNTIME_PATH;
        if(!is_dir($runPath."tracelog")){
            mkdir($runPath."tracelog",0777,true);
            @chown($runPath."tracelog",'www');
            @chgrp($runPath."tracelog",'www');
        }
        $dir = $runPath."tracelog/".date("Ymd",time());
        if(!is_dir($dir)){
            mkdir($dir,0777,true);
            @chown($dir,'www');
            @chgrp($dir,'www');
        }

        $message = date('Y-m-d H:i:s',$time).'>>'.$ip."》》{$log}\n";
        $file = $dir."/{$index}.log";
        if(!file_exists($file)){
            @touch($file);
            @chmod($file,0777);
        }
        error_log($message, 3, $file);

        $file_sort = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
        $size = filesize($file);
        $limit_size = 1024*1024*3-1024*10;
        $fileName = $index;
        if($size> $limit_size){
            foreach ($file_sort as $bianhao){
                $bianhaoFile = $dir."/".$fileName.".back{$bianhao}.log";
                if(!file_exists($bianhaoFile)){
                    rename($file,$bianhaoFile);
                    break;
                }
            }
        }
    }


    /**
     * 格式化 数据打印 程序可继续执行
     * 可以传入多个参数
     * pp($name)   pp($arr,$pwd,$obj)
     */
    function pp(){
        $arg_list = func_get_args(); //参数数组

        $numargs = func_num_args(); //参数数量

        echo "<pre>";
        for($i=0;$i<$numargs;$i++){
            print_r($arg_list[$i]);
            echo "</pre>".PHP_EOL;
            echo "<pre>";
        }
        echo "</pre>".PHP_EOL;
    }
    /**
     * 格式化 数据打印 程序终止
     * 可以传入多个参数
     * pp($name)   pp($arr,$pwd,$obj)
     */
    function ppd(){
        $arg_list = func_get_args(); //参数数组

        $numargs = func_num_args(); //参数数量

        echo "<pre>";
        for($i=0;$i<$numargs;$i++){
            print_r($arg_list[$i]);
            echo "</pre>";
            echo "<pre>";
        }
        echo "</pre>";
        die();
    }
    /**
     * 获取客户端真实IP
     * @return mixed|string
     */
    function getRealIP(){
        $forwarded = request()->header("x-forwarded-for");
        if($forwarded){
            $ip = explode(',',$forwarded)[0];
        }else{
            $ip = request()->ip();
        }
        return $ip;
    }
    function requestHttpCurl($url,$data,$timeout=60,$head=[],$custom_request = ''){
        if(is_array($data)){
    //        trace_log("修改参数后".json_encode($data),$this->payway_bianhao);
        }else{
    //        trace_log("修改参数后".$data,$this->payway_bianhao);
        }

        //定义提交内容类型
        // 设置请求头
        $headers = array(
            'Content-Type: application/json;charset=utf-8',
            'Accept: application/json',
        );
        if(!empty($head)){
            if($head[0] == 'nomerge'){
                unset($head[0]);
                $headers = $head;
            }else{
                $headers = array_merge($headers,$head);
            }
        }
        $curl = curl_init(); // 启动一个CURL会话
        curl_setopt($curl, CURLOPT_URL, $url); // 要访问的地址
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0); // 对认证证书来源的检查
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0); // 从证书中检查SSL加密算法是否存在
    //        curl_setopt($curl, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']); // 模拟用户使用的浏览器
        curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1); // 使用自动跳转
        curl_setopt($curl, CURLOPT_AUTOREFERER, 1); // 自动设置Referer
        if(!empty($data)){
            curl_setopt($curl, CURLOPT_POST, 1); // 发送一个常规的Post请求
    //        curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($data)); // Post提交的数据包
            curl_setopt($curl, CURLOPT_POSTFIELDS, $data); // Post提交的数据包
        }
        if(!empty($custom_request)){
            curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $custom_request); //请求方式
        }
        curl_setopt($curl, CURLOPT_TIMEOUT, $timeout); // 设置超时限制防止死循环
        curl_setopt($curl, CURLOPT_HEADER, 0); // 显示返回的Header区域内容
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); // 获取的信息以文件流的形式返回
        curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
        $httpcode = curl_getinfo($curl,CURLINFO_HTTP_CODE);
        $result = curl_exec($curl); // 执行操作
        $curlError = curl_errno($curl);

        //超时重试模式
        $retries = 2;
        while((!$result) && $retries--){
            $result = curl_exec($curl);
        }
        if(empty($result)){
            trace_log("{$url}获取api结果空状态码{$httpcode}-错误码{$curlError}".curl_error($curl),'common_curlError');
            return ['code'=>1212,'msg'=>'request time out please waite for a moment','data'=>[]];
        }

        if ($curlError) {
            trace_log("{$url}获取api结果错误la 状态码{$httpcode}-错误码{$curlError}".curl_error($curl),'common_curlError');
            trace_log("{$url}获取api结果错误la，状态码{$httpcode}-错误码{$curlError}".curl_error($curl)."\n============================================================",'common_curlError');
            return ['code'=>1212,'msg'=>"curl有错误码是{$curlError}==".curl_error($curl),'data'=>[]];
        }
        curl_close($curl); // 关闭CURL会话


        return [
            'code' => 0,
            'msg' => 'ok!',
            'data' => json_decode($result,true)
        ];
    }
    /**
     * 生成区间内的随机小数
     * @param int $min
     * @param int $max
     * @return float
     */
    function getRandFloat($min = 0, $max = 1){
        return round($min + mt_rand() / mt_getrandmax() * ($max - $min),2);

    }

    /**
     * 简单对称加密算法之加密
     * @param String $string 需要加密的字串
     * @param String $skey 加密EKY
     * @author Anyon Zou <zoujingli@qq.com>
     * @date 2013-08-13 19:30
     * @update 2014-10-10 10:10
     * @return String
     */
    function aes_encryption_encode($string = '', $skey = 'api') {
        $data = openssl_encrypt($string, 'AES-128-ECB', $skey, 0);
        $data = base64_encode($data);

        return $data;
    }
    /**
     * 简单对称加密算法之解密
     * @param String $string 需要解密的字串
     * @param String $skey 解密KEY
     * @author Anyon Zou <zoujingli@qq.com>
     * @date 2013-08-13 19:30
     * @update 2014-10-10 10:10
     * @return String
     */
    function aes_encryption_decode($string = '', $skey = 'api') {
        $decrypted = openssl_decrypt(base64_decode($string), 'AES-128-ECB', $skey,0);
        return $decrypted;
    }
    /**
     * 从头部获取token
     * @return bool|string
     */
    function getHeaderToken() {
        $header = request()->header();
        if (isset($header['authorization'])) {
            return substr($header['authorization'], 7);
        }

        return '';
    }
    /**
     * 设置jwt
     * @param $data
     * @return string
     */
    function setJWT($data) {
        $jwt   = new Firebase\JWT\JWT();
        $token = [
            // "iss"  => "http://example.org", // 签发者
            // "aud"  => "http://example.com", // 认证者
            'iat'  => time(), // 签发时间
            'nbf'  => time(), // 生效时间
            'exp'  => (time() + 60 * 60 * 24 * 7), // 过期时间  7天后的时间戳
            'data' => $data
        ];

        return $jwt::encode($token, config('global.jwt_key'), 'HS256');
    }

    /**
     * 获取token中的信息
     * @param $token
     * @return array|null
     */
    function getJWT($token) {
        $jwt  = new Firebase\JWT\JWT();
        $data = ['id'=>0];
        try {
            $jwtData = $jwt::decode($token, new Firebase\JWT\Key(config('global.jwt_key'), 'HS256'));
            $data     = (array) ($jwtData->data);
        } catch (\Exception $e) {
           trace_log($e->getMessage(),"getjwt_error");
            return $data;
        }
        return $data;
    }

function jsonReturn($code, $msg = 'success', $data = [])
{
    return json(['code' => $code, 'data' => $data, 'msg' => $msg]);
}
function dataReturn($code, $msg = 'success', $data = [])
{
    return ['code' => $code, 'data' => $data, 'msg' => $msg];
}
/**
 * 获取配置
 * @param $type
 * @return array
 */
function getConfByType($type) {
    try {
        $config = db('config')->where(['group' => $type])->select();
        $formatConfig = [];
        foreach ($config as $vo) {
            $formatConfig[$vo['name']] = $vo['value'];
        }

        return $formatConfig;
    } catch (\Exception $e) {
        return [];
    }
}
function getEncryptPassword($password, $salt = '')
{
    return md5(md5($password) . $salt);
}
/**
 * 随机头像
 * @param $id
 * @return string|array
 */
function getRandAvtar($id = 0)
{
    $arr = [1, 2, 3,4];
    $api = request()->domain();
    $api = '';
    if ($id == 0) {
        $num = $arr[array_rand($arr)];
        return $api . '/assets/img/avatar-' . $num . '.png';
    }

    $avatar = [];
    foreach ($arr as $vo) {
        $avatar[] = $api . '/assets/img/avatar-' . $vo . '.png';
    }

    return $avatar;
}
function arrayToXML($data){
    if (!is_array($data) || count($data) <= 0) {
        return '';
    }

    $xml = '<xml>';
    foreach ($data as $key => $val) {
        $xml .= is_numeric($val) ? '<'.$key.'>'.$val.'</'.$key.'>' :
            '<'.$key.'><![CDATA['.$val.']]></'.$key.'>';
    }
    $xml .= '</xml>';

    return $xml;
}
/**
 * get 提交
 * @param $url
 * @param $data
 * @return mixed
 */
function curlGet($url, $data= '')
{
    $ch = curl_init();
    if(!empty($data)){
        curl_setopt($ch, CURLOPT_URL, $url . '?' . http_build_query($data));
    }else{
        curl_setopt($ch, CURLOPT_URL, $url);
    }
    curl_setopt($ch, CURLOPT_HEADER, 0);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);;
    $output = curl_exec($ch);
    curl_close($ch);

    return json_decode($output,true);
}
function checkNoChineseAndLetters($string) {
    if(empty($string)){
        return ['code'=>1005,'msg'=>__('Mobile is error'),'data'=>$string];
    }
    $string = trim($string);
    $string = trim($string,'+');
    // 正则表达式：没有中文字符（[\x{4e00}-\x{9fa5}] 是 Unicode 中文字符的范围）且没有字母（[a-zA-Z]）
    // 注意：这个正则表达式只考虑了基本的中文字符范围，不包括扩展字符或其他东亚字符
    if (preg_match('/^[^\x{4e00}-\x{9fa5}a-zA-Z]+$/u', $string)) {
        $sms_hk = config('global.sms_hk');
        if($sms_hk){
            //香港电话
            if(strlen($string) == 8){
                return ['code'=>0,'msg'=>'ok','data'=>"852".$string];
            }else if(strlen($string) == 11){
                $pre = mb_substr($string,0,3);
                if($pre != '852'){
                    return ['code'=>1005,'msg'=>__('Only supports Hong Kong phone calls'),'data'=>$string];
                }else{
                    return ['code'=>0,'msg'=>'ok','data'=>$string];
                }
            }else{
                return ['code'=>1005,'msg'=>__('Only supports Hong Kong phone calls'),'data'=>$string];
            }
        }else{
            //国内电话只能11个
            if(strlen($string) == 11){
                return ['code'=>0,'msg'=>'ok','data'=>$string];
            }else{
                return ['code'=>1005,'msg'=>__('Mobile is error'),'data'=>$string];
            }
        }
    }
    return ['code'=>1005,'msg'=>__('Mobile is error'),'data'=>$string];


}

function formateAount($amout){
    if(empty($amout))
        return 0;

    return number_format($amout,2,'.',',');
}
function generateDateRange($period) {
    $now = new \DateTime();
    $dates = [];
    $intervals = [
        'half_year' => 6, // 6 months
        'one_year' => 12, // 12 months
        'two_years' => 24, // 24 months
        'three_years' => 36, // 36 months
    ];


    // Clone the current date to avoid modifying the original $now object
    $endDate = clone $now;
    $startDate = clone $endDate;

    // Subtract the required number of months from the start date
    $startDate->modify('-' . $intervals[$period] . ' month');

    // Generate dates in the specified range
    for ($i = 0; $i <= $intervals[$period]; $i++) {
        // Clone the start date to avoid modifying it in the loop
        $date = clone $startDate;
        $date->modify('+' . $i . ' month');
        $dates[] = $date->format('Y-m');
    }

    return $dates;
}
//判断是什么平台
function platform()
{
    //ll($_SERVER['HTTP_USER_AGENT']);
    $platform='h5';
    $a_strtolower = strtolower($_SERVER['HTTP_USER_AGENT']);
    trace_log("HTTP_USER_AGENT是".$a_strtolower,'params_token');
    if(strpos($a_strtolower, "micromessenger"))//公众号MicroMessenger
    {
        if(strpos($a_strtolower, "miniprogram"))//小程序
        {
            $platform = 'xcxapp';
        }
        else
            $platform = 'wxapp';

    }
    elseif(strpos($a_strtolower, "uni-app") || strpos($a_strtolower, "Html5Plus"))//app
    {
        $platform = 'app';
    }
    return $platform;
}
